Singleton Pattern and Thread Safety
A Singleton restricts a type to a single instance within a defined scope and provides a controlled way to access it. The major concerns are concurrent initialization, publication visibility, lifecycle management and hidden global state. In modern applications I avoid Singleton unless single-instance semantics are genuinely required. When it is required, I prefer language-supported safe initialization or dependency injection with an application-scoped lifetime over hand-written global state.
Naive lazy initialization can create multiple instances under concurrent access.
Synchronization or language/runtime-supported initialization can provide safety.
Double-checked locking requires correct memory-visibility semantics; in Java it requires volatile.
Singletons can introduce hidden dependencies and global mutable state.
Tests can become order-dependent when Singleton state persists.
Prefer application-scoped dependency injection when the real requirement is one instance per application.